"""Region selection dialog used when cropping the input image."""

from __future__ import annotations

from typing import Optional, Tuple

import numpy as np

from PyQt5.QtCore import QPoint, QRect, QSize, Qt
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import (
    QDialog,
    QDialogButtonBox,
    QLabel,
    QVBoxLayout,
    QWidget,
    QRubberBand,
)

from ..core.utils import to_display

class RegionSelectionView(QLabel):
    def __init__(self, image: np.ndarray, max_display: int = 900) -> None:
        super().__init__()
        display = to_display(image)
        height, width = display.shape[:2]
        scale = 1.0
        if max(height, width) > max_display:
            scale = max_display / max(height, width)
        scaled_width = int(width * scale)
        scaled_height = int(height * scale)
        scaled_height = max(1, scaled_height)
        scaled_width = max(1, scaled_width)
        self._scale = scale
        self._image_width = width
        self._image_height = height
        qimg = QImage(
            display.data,
            width,
            height,
            display.shape[1] * display.shape[2],
            QImage.Format_BGR888,
        )
        pixmap = QPixmap.fromImage(qimg).scaled(
            scaled_width,
            scaled_height,
            Qt.KeepAspectRatio,
            Qt.SmoothTransformation,
        )
        self.setPixmap(pixmap)
        self.setFixedSize(pixmap.size())
        self.setAlignment(Qt.AlignCenter)
        self._origin = None  # type: Optional[QPoint]
        self._rubber_band = QRubberBand(QRubberBand.Rectangle, self)
        self._selection = QRect()

    def mousePressEvent(self, event) -> None:  # type: ignore[override]
        if event.button() != Qt.LeftButton:
            return
        self._origin = event.pos()
        self._rubber_band.setGeometry(QRect(self._origin, QSize()))
        self._rubber_band.show()

    def mouseMoveEvent(self, event) -> None:  # type: ignore[override]
        if self._origin is None:
            return
        rect = QRect(self._origin, event.pos()).normalized()
        rect = rect.intersected(self.rect())
        self._rubber_band.setGeometry(rect)

    def mouseReleaseEvent(self, event) -> None:  # type: ignore[override]
        if event.button() != Qt.LeftButton or self._origin is None:
            return
        rect = QRect(self._origin, event.pos()).normalized()
        rect = rect.intersected(self.rect())
        self._rubber_band.hide()
        self._selection = rect
        self._origin = None

    def selected_region(self) -> Optional[Tuple[int, int, int, int]]:
        if self._selection.isNull() or self._selection.width() < 5 or self._selection.height() < 5:
            return None
        scale = 1.0 / self._scale if self._scale > 0 else 1.0
        x = int(self._selection.x() * scale)
        y = int(self._selection.y() * scale)
        w = int(self._selection.width() * scale)
        h = int(self._selection.height() * scale)
        x = max(0, min(x, self._image_width - 1))
        y = max(0, min(y, self._image_height - 1))
        if x + w > self._image_width:
            w = self._image_width - x
        if y + h > self._image_height:
            h = self._image_height - y
        if w <= 0 or h <= 0:
            return None
        return (x, y, w, h)


class RegionSelectionDialog(QDialog):
    def __init__(self, image: np.ndarray, parent: Optional[QWidget] = None) -> None:
        super().__init__(parent)
        self.setWindowTitle("Select Region")
        layout = QVBoxLayout(self)
        info = QLabel("Drag to select the area to process. Cancel to keep the entire image.")
        info.setWordWrap(True)
        layout.addWidget(info)
        self.viewer = RegionSelectionView(image)
        layout.addWidget(self.viewer, alignment=Qt.AlignCenter)
        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        layout.addWidget(buttons)

    def get_selection(self) -> Optional[Tuple[int, int, int, int]]:
        return self.viewer.selected_region()


